<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=975261
-->
<head>
  <meta charset="utf-8">
  <title>Test OMTA animations start correctly (Bug 975261)</title>
  <script type="application/javascript"
    src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="application/javascript"
    src="/tests/SimpleTest/paint_listener.js"></script>
  <script type="application/javascript" src="animation_utils.js"></script>
  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
  <style type="text/css">
    @keyframes anim-opacity {
       0% { opacity: 0.5 }
       100% { opacity: 0.5 }
    }
    @keyframes anim-opacity-2 {
       0% { opacity: 0.0 }
       100% { opacity: 1.0 }
    }
    @keyframes anim-transform {
       0% { transform: translate(50px); }
       100% { transform: translate(50px); }
    }
    @keyframes anim-transform-2 {
       0% { transform: translate(0px); }
       100% { transform: translate(100px); }
    }
    .target {
      /* These two lines are needed so that an opacity/transform layer
       * already exists when the animation is applied. */
      opacity: 0.99;
      transform: translate(99px);

      /* Element needs geometry in order to be animated on the
       * compositor. */
      width: 100px;
      height: 100px;
      background-color: white;
    }
  </style>
</head>
<body>
<a target="_blank"
  href="https://bugzilla.mozilla.org/show_bug.cgi?id=975261">Mozilla Bug
  975261</a>
<div id="display"></div>
<pre id="test">
<script type="application/javascript">
"use strict";

var gUtils = SpecialPowers.DOMWindowUtils;

SimpleTest.waitForExplicitFinish();
runOMTATest(testDelay, SimpleTest.finish);

function newTarget() {
  var target = document.createElement("div");
  target.classList.add("target");
  document.getElementById("display").appendChild(target);
  return target;
}

function testDelay() {
  gUtils.advanceTimeAndRefresh(0);

  var target = newTarget();
  target.setAttribute("style", "animation: 10s 10s anim-opacity linear");
  gUtils.advanceTimeAndRefresh(0);

  waitForAllPaints(function() {
    gUtils.advanceTimeAndRefresh(10100);
    waitForAllPaints(function() {
      var opacity = gUtils.getOMTAStyle(target, "opacity");
      is(opacity, "0.5",
         "opacity is set on compositor thread after delayed start");
      target.removeAttribute("style");
      gUtils.restoreNormalRefresh();
      testTransform();
    });
  });
}

function testTransform() {
  gUtils.advanceTimeAndRefresh(0);

  var target = newTarget();
  target.setAttribute("style", "animation: 10s 10s anim-transform linear");
  gUtils.advanceTimeAndRefresh(0);

  waitForAllPaints(function() {
    gUtils.advanceTimeAndRefresh(10100);
    waitForAllPaints(function() {
      var transform = gUtils.getOMTAStyle(target, "transform");
      ok(matricesRoughlyEqual(convertTo3dMatrix(transform),
                              convertTo3dMatrix("matrix(1, 0, 0, 1, 50, 0)")),
         "transform is set on compositor thread after delayed start");
      target.remove();
      gUtils.restoreNormalRefresh();
      testBackwardsFill();
    });
  });
}

function testBackwardsFill() {
  gUtils.advanceTimeAndRefresh(0);

  var target = newTarget();
  target.setAttribute("style",
    "transform: translate(30px); " +
    "animation: 10s 10s anim-transform-2 linear backwards");

  gUtils.advanceTimeAndRefresh(0);
  waitForAllPaints(function() {
    gUtils.advanceTimeAndRefresh(10000);
    waitForAllPaints(function() {
      gUtils.advanceTimeAndRefresh(100);
      waitForAllPaints(function() {
        var transform = gUtils.getOMTAStyle(target, "transform");
        ok(matricesRoughlyEqual(convertTo3dMatrix(transform),
                                convertTo3dMatrix("matrix(1, 0, 0, 1, 1, 0)")),
           "transform is set on compositor thread after delayed start " +
           "with backwards fill");
        target.remove();
        gUtils.restoreNormalRefresh();
        testTransitionTakingOver();
      });
    });
  });
}

function testTransitionTakingOver() {
  gUtils.advanceTimeAndRefresh(0);

  var parent = newTarget();
  var child = newTarget();
  parent.appendChild(child);
  parent.style.opacity = "0.0";
  parent.style.animation = "10s anim-opacity-2 linear";
  child.style.opacity = "inherit";
  child.style.transition = "10s opacity linear";

  var childCS = getComputedStyle(child, "");

  gUtils.advanceTimeAndRefresh(0);
  waitForAllPaints(function() {
    gUtils.advanceTimeAndRefresh(4000);
    waitForAllPaints(function() {
      child.style.opacity = "1.0";
      var opacity = gUtils.getOMTAStyle(child, "opacity");
      // FIXME Bug 1039799 (or lower priority followup): Animations
      // inherited from an animating parent element don't get shipped to
      // the compositor thread.
      todo_is(opacity, "0.4",
         "transition that interrupted animation is correct");

      // Trigger to start the transition, without this the transition will
      // be pending in advanceTimeAndRefresh(0) so the transition will not
      // be sent to the compositor until we call advanceTimeAndRefresh with
      // a positive time value.
      getComputedStyle(child).opacity;
      gUtils.advanceTimeAndRefresh(0);
      waitForAllPaints(function() {
        var opacity = gUtils.getOMTAStyle(child, "opacity");
        is(opacity, "0.4",
           "transition that interrupted animation is correct");
        gUtils.advanceTimeAndRefresh(5000);
        waitForAllPaints(function() {
          opacity = gUtils.getOMTAStyle(child, "opacity");
          is(opacity, "0.7",
             "transition that interrupted animation is correct");
          is(childCS.opacity, "0.7",
             "transition that interrupted animation is correct");
          parent.remove();
          gUtils.restoreNormalRefresh();
          SimpleTest.finish();
        });
      });
    });
  });
}

</script>
</pre>
</body>
</html>
